<!DOCTYPE html>
<html>
	<head>
		<title>Minesweeper - DOM</title>
		<script src="../../Dependencies/src/?need=M4,M4Tween"></script>
		<link href="../../common/docs/docs.css" rel="stylesheet" type="text/css">
		<style type="text/css">
			#container.content{background:rgb(192,192,192);}
			.ui{margin:0 auto 10px;padding:1px;height:31px;border-left:solid 2px rgb(128, 128, 128);border-top:solid 2px rgb(128, 128, 128);border-right:solid 2px rgb(255, 255, 255);border-bottom:solid 2px rgb(255, 255, 255);}

			.ui .counter{margin-top:4px;height:23px;width:39px;border-left:solid 2px rgb(160, 160, 160);border-top:solid 2px rgb(160, 160, 160);border-right:solid 2px rgb(231, 231, 231);border-bottom:solid 2px rgb(231, 231, 231);}
			.ui .counter.mine{float:left;margin-left:4px;}
			.ui .counter.time{float:right;margin-right:4px;}
			.ui .counter .number{width:13px;height:23px;background:url(imgs/minesweeper.png) no-repeat;float:left;}
			.ui .counter .number[title="0"]{background-position:-128px -2px;}
			.ui .counter .number[title="1"]{background-position:-2px -2px;}
			.ui .counter .number[title="2"]{background-position:-16px -2px;}
			.ui .counter .number[title="3"]{background-position:-30px -2px;}
			.ui .counter .number[title="4"]{background-position:-44px -2px;}
			.ui .counter .number[title="5"]{background-position:-58px -2px;}
			.ui .counter .number[title="6"]{background-position:-72px -2px;}
			.ui .counter .number[title="7"]{background-position:-86px -2px;}
			.ui .counter .number[title="8"]{background-position:-100px -2px;}
			.ui .counter .number[title="9"]{background-position:-114px -2px;}

			.field{margin:0 auto;border-left:solid 3px rgb(128, 128, 128);border-top:solid 3px rgb(128, 128, 128);border-right:solid 3px rgb(255, 255, 255);border-bottom:solid 3px rgb(255, 255, 255);}

			.field .lb{clear:both;}
			.field .square,.field .square[rel="flag"]:active,.field .square[rel="dunno"]:active{float:left;cursor:pointer;width:12px;height:12px;border-left:solid 2px rgb(255, 255, 255);border-top:solid 2px rgb(255, 255, 255);border-right:solid 2px rgb(128, 128, 128);border-bottom:solid 2px rgb(128, 128, 128);}
			.field .square[rel="flag"]{background:url(imgs/minesweeper.png) no-repeat -38px -55px;}
			.field .square[rel="dunno"]{background:url(imgs/minesweeper.png) no-repeat -55px -55px;}
			.field .square[rel="empty_1"]{background:url(imgs/minesweeper.png) no-repeat -3px -71px;}
			.field .square[rel="empty_2"]{background:url(imgs/minesweeper.png) no-repeat -20px -71px;}
			.field .square[rel="empty_3"]{background:url(imgs/minesweeper.png) no-repeat -37px -71px;}
			.field .square[rel="empty_4"]{background:url(imgs/minesweeper.png) no-repeat -54px -71px;}
			.field .square[rel="empty_5"]{background:url(imgs/minesweeper.png) no-repeat -71px -71px;}
			.field .square[rel="empty_6"]{background:url(imgs/minesweeper.png) no-repeat -88px -71px;}
			.field .square[rel="empty_7"]{background:url(imgs/minesweeper.png) no-repeat -105px -71px;}
			.field .square[rel="empty_8"]{background:url(imgs/minesweeper.png) no-repeat -122px -71px;}
			.field .square[rel="mine"]{background:url(imgs/minesweeper.png) no-repeat -88px -54px;}
			.field .square[rel="triggered_mine"]{background:url(imgs/minesweeper.png) no-repeat -105px -54px;}
			.field .square:active,
			.field .square[rel="empty_0"],
			.field .square[rel="empty_1"],
			.field .square[rel="empty_2"],
			.field .square[rel="empty_3"],
			.field .square[rel="empty_4"],
			.field .square[rel="empty_5"],
			.field .square[rel="empty_6"],
			.field .square[rel="empty_7"],
			.field .square[rel="empty_8"],
			.field .square[rel="mine"],
			.field .square[rel="triggered_mine"]{width:15px;height:15px;border-left:solid 1px rgb(128, 128, 128);border-top:solid 1px rgb(128, 128, 128);border-bottom:none;border-right: none;}
		</style>
	</head>
	<body oncontextmenu="return false;" onload="init()">
		<header><h1>Minesweeper - DOM</h1></header>
		<div id="container" class="content">
			<div id="minesweeper" data-cols="15" data-rows="15" data-mines="30">

			</div>
		</div>
		<script type="text/javascript">

			var ms;
			
			function init()
			{
				ms = new MineSweeper(document.querySelector("#minesweeper"));
			}

			function MineSweeper(pElement)
			{
				this.$ = {};
				this.$.parent = pElement;
				this.setup(this.$.parent.dataset.cols, this.$.parent.dataset.rows, this.$.parent.dataset.mines);
			}

			Class.define(MineSweeper, [EventDispatcher],
			{
				setup:function(pCols, pRows, pMines)
				{
					this.field = {x:pCols, y:pRows};
					this.totalMines = Math.min(pMines, pCols*pRows);

					this.squares = [];
					for(var i = 0; i<this.field.y; i++)
						this.squares[i] = [];

					this._prepareUI();
					this._prepareField();
					this._harmonize();
					this.startGame();
				},
				_prepareUI:function()
				{
					if(!this.$.ui)
						this.$.ui = M4.createElement("div", {parentNode:this.$.parent, class:"ui"});
					if(!this.$.mineCounter)
						this.$.mineCounter = new Counter(this.$.ui, "mine");
					if(!this.$.timer)
						this.$.timer = new Counter(this.$.ui, "time");
				},
				_prepareField:function()
				{
					if(!this.$.field)
						this.$.field = M4.createElement("div", {parentNode:this.$.parent, class:"field"});
					this.$.field.innerHTML = "";
					var ref = this;
					this.squares.forEach(function(line)
					{
						for(var i = 0;i<ref.field.x;i++)
						{
							line[i] = new Square(ref.$.field);
							line[i].addEventListener(MineSweeper.EVT_EXPLODING, ref._explode.proxy(this));
						}
						M4.createElement("div", {parentNode:ref.$.field, "class":"lb"});//Line breaker
					});
					var tx, ty, s;
					for(var i = 0;i<this.totalMines; i++)
					{
						tx = Math.floor(Math.random() * this.field.x);
						ty = Math.floor(Math.random() * this.field.y);
						s = this.squares[tx][ty];
						if(s.isMine)
							i--;
						else
							s.setMine();
					}

					var n, max = this.field.y, maxj = this.field.x;
					for(i = 0; i<max;i++)
					{
						for(var j = 0; j<maxj;j++)
						{
							n = [];
							if(i>0)
							{
								if(j>0)
									n.push(this.squares[i-1][j-1]);
								n.push(this.squares[i-1][j]);
								if(j<maxj-1)
									n.push(this.squares[i-1][j+1])
							}
							if(j>0)
								n.push(this.squares[i][j-1]);
							if(j<maxj-1)
								n.push(this.squares[i][j+1]);
							if(i<max-1)
							{
								if(j>0)
									n.push(this.squares[i+1][j-1]);
								n.push(this.squares[i+1][j]);
								if(j<maxj-1)
									n.push(this.squares[i+1][j+1]);
							}
							this.squares[i][j].setNeighborhood(n);
						}
					}
				},
				_harmonize:function()
				{
					var width = this.squares[0][0].getWidth() * this.field.x+"px";
					this.$.field.style.width = width;
					this.$.field.style.height = this.squares[0][0].getHeight() * this.field.y+"px";
					this.$.ui.style.width = width;
				},
				_explode:function()
				{
					var i, j, max, maxj;
					for(i = 0, max = this.field.y; i<max;i++)
					{
						for(j = 0, maxj = this.field.x; j<maxj;j++)
							this.squares[i][j].explode();
					}
					this.dispatchEvent(new Event(MineSweeper.GAME_OVER, false));
				},
				startGame:function()
				{
					this.$.mineCounter.update(this.totalMines);
					this.$.timer.update(0);
				}
			});

			MineSweeper.EVT_GAME_OVER = "evt_game_over";
			MineSweeper.EVT_GAME_WIN = "evt_game_win";
			MineSweeper.EVT_RESTART = "evt_restart";
			MineSweeper.EVT_START = "evt_start";
			MineSweeper.EVT_EXPLODING = "evt_exploding";
			MineSweeper.EVT_DEDUCT = "evt_deduct";
			MineSweeper.EVT_COUNT = "evt_count";

			function Square(pParentNode)
			{
				this.$ = {};
				this.isMine = false;
				this.neighbors = [];
				this.dangerousNeighbors = 0;
				this._triggered = false;
				this.$.element = M4.createElement("div", {"parentNode":pParentNode, "class":"square", rel:"default"});
				this._anoUpHandler = this._upHandler.proxy(this);
				this.$.element.addEventListener("mouseup", this._anoUpHandler);
			}

			Class.define(Square, [EventDispatcher],
			{
				_upHandler:function(e)
				{
					if(this._triggered)
						return;
					console.log(this);
					switch(e.button)
					{
						case 0:
							switch(this.$.element.getAttribute("rel"))
							{
								case "flag":
									return;
									break;
							}
							break;
						case 2:
							switch(this.$.element.getAttribute("rel"))
							{
								case "default":
									this.dispatchEvent(new Event(MineSweeper.EVT_DEDUCT, false));
									this.$.element.setAttribute("rel", "flag");
									break;
								case "flag":
									this.dispatchEvent(new Event(MineSweeper.EVT_COUNT, false));
									this.$.element.setAttribute("rel", "dunno");
									break;
								default:
									this.$.element.setAttribute("rel", "default");
								break;
							}
							return;
							break;
						default:
							return;
							break;
					}

					this._triggered = true;

					if(!this.isMine&&this.dangerousNeighbors==0)
					{
						this.neighbors.forEach(function(neighbor)
						{
							neighbor.trigger();
						});
					}

					if(this.isMine)
						this.dispatchEvent(new Event(MineSweeper.EVT_EXPLODING, false));

					var rel = this.isMine ? "triggered_mine":"empty_"+this.dangerousNeighbors;
					this.$.element.setAttribute("rel", rel);
					this.$.element.removeEventListener("mouseup", this._anoUpHandler);

				},
				getWidth:function()
				{
					return this.$.element.offsetWidth;
				},
				getHeight:function()
				{
					return this.$.element.offsetHeight;
				},
				setMine:function()
				{
					this.isMine = true;
				},
				setNeighborhood:function(pNeighbors)
				{
					this.neighbors = pNeighbors;
					var ref = this;
					this.neighbors.forEach(function(neighbor)
					{
						if(neighbor.isMine)
							ref.dangerousNeighbors++;
					});
				},
				trigger:function()
				{
					this._upHandler({button:0});
				},
				explode:function()
				{
					this.removeAllEventListeners();
					if(!this.isMine||this.currentState == "triggered_mine")
						return;
					this.$.element.setAttribute("rel", "mine");
				},
				removeAllEventListeners:function()
				{
					this.$.element.removeEventListener("mouseup", this._anoUpHandler);
				}
			});

			function Counter(pParentNode, pClassName)
			{
				this.$ = {};
				this.$.element = M4.createElement("div", {parentNode:pParentNode, class:pClassName+" counter"});
				this.$.numbers = [];
				this.$.numbers[0] = M4.createElement("div", {parentNode:this.$.element, class:"number"});
				this.$.numbers[1] = M4.createElement("div", {parentNode:this.$.element, class:"number"});
				this.$.numbers[2] = M4.createElement("div", {parentNode:this.$.element, class:"number"});
				this.update(0);
			}

			Class.define(Counter, [Class],
			{
				update:function(pValue)
				{
					var a = Math.floor(pValue/100);
					var b = Math.floor((pValue - (a*100))/10);
					var c = pValue - (a*100) - (b*10);
					this.$.numbers[0].setAttribute("title", a);
					this.$.numbers[1].setAttribute("title", b);
					this.$.numbers[2].setAttribute("title", c);
				}
			});

		</script>
	</body>
</html>